/*
 * GameComponent.cpp
 *
 *  Created on: May 12, 2012
 *      Author: mklingen
 */

#include "GameComponent.h"
#include "../MathUtils.h"
#include <iostream>
namespace kling
{


    GameComponent::GameComponent(GameComponentManager* componentManager, std::string name, GlobalComponentID globalID) :
            m_globalID(globalID), m_name(name), m_maxLocalID(0), m_isInitialized(false), m_isDestroyed(false), m_componentManager(componentManager)
    {
        m_parent = NULL;
        m_globalPose.setIdentity();
        m_localPose.setIdentity();
        m_localRotation = 0;
        m_globalRotation = 0;
    }

    GameComponent::~GameComponent()
    {
        m_isInitialized = false;
        m_children.clear();
        m_name = "DEAD";
        m_localID = INVALID_LOCAL_ID;
        m_globalID = INVALID_GLOBAL_ID;
    }

    GameComponent* GameComponent::GetChildByLocalID(LocalComponentID localID)
    {
        if(!ContainsChildWithLocalID(localID))
        {
            return NULL;
        }
        else
        {
            return m_children[localID];
        }
    }


    std::vector<GameComponent*> GameComponent::GetAllChildrenWithName(const std::string& name)
    {
        std::vector<GameComponent*> toReturn;

        for(std::map<LocalComponentID, GameComponent*>::iterator it = m_children.begin(); it != m_children.end(); it++)
        {
            if(it->second->GetName() == name)
            {
                toReturn.push_back(it->second);
            }
        }

        return toReturn;
    }


    GameComponent* GameComponent::GetFirstChildByName(const std::string& name)
    {
        for(std::map<LocalComponentID, GameComponent*>::iterator it = m_children.begin(); it != m_children.end(); it++)
        {
            if(it->second->GetName() == name)
            {
                return it->second;
            }
        }

        return NULL;

    }

    GameComponent* GameComponent::GetChildByGlobalID(GlobalComponentID globalID)
    {
        for(std::map<LocalComponentID, GameComponent*>::iterator it = m_children.begin(); it != m_children.end(); it++)
        {
            if(it->second->GetGlobalID() == globalID)
            {
                return it->second;
            }
        }

        return NULL;
    }

    bool GameComponent::ContainsChildWithLocalID(LocalComponentID localID)
    {
        return m_children.find(localID) != m_children.end();
    }

    bool GameComponent::ContainsChildWithGlobalID(GlobalComponentID globalID)
    {
        return GetChildByGlobalID(globalID) != NULL;
    }

    bool GameComponent::AddChild(GameComponent* child, LocalComponentID localID)
    {
        if(ContainsChildWithGlobalID(child->GetGlobalID()))
        {
            return false;
        }
        else
        {
            if(localID == INVALID_LOCAL_ID)
            {
                localID = this->GetNextLocalID();
            }
            else if(ContainsChildWithLocalID(localID))
            {
                return false;
            }

            child->SetLocalID(localID);
            m_children[localID] = child;
            child->SetParent(this);
        }
    }


    void GameComponent::ComputeGlobalPoseRecursive()
    {
        if(m_parent != NULL)
        {
            m_globalPose =  m_parent->GetGlobalPose() * m_localPose ;
            m_globalRotation = m_parent->GetGlobalRotation() + m_localRotation;
        }
        else
        {
            m_globalPose = m_localPose;
            m_globalRotation = m_localRotation;
        }

        for(std::map<LocalComponentID, GameComponent*>::iterator it = m_children.begin(); it != m_children.end(); it++)
        {
            it->second->ComputeGlobalPoseRecursive();
        }
    }


    void GameComponent::Update(double deltaTimeSeconds)
    {
        // Do nothing for now.
    }

    void GameComponent::Render(double deltaTimeSeconds)
    {
        // Do nothing for now.
    }

    void GameComponent::Initialize()
    {
        m_isInitialized = true;
    }



    bool GameComponent::RemoveChild(GameComponent* child, bool destroy)
    {
        std::map<LocalComponentID, GameComponent*>::iterator toRemove = m_children.end();
        for(std::map<LocalComponentID, GameComponent*>::iterator it = m_children.begin(); it != m_children.end(); it++)
        {
            if(it->second == child)
            {
                toRemove = it;
            }
        }

        if(toRemove != m_children.end())
        {
            m_children.erase(child->GetLocalID());
            child->SetParent(NULL);
            child->SetLocalID(INVALID_LOCAL_ID);

            if(destroy)
            {
                child->Destroy();
            }

            return true;
        }

        return false;
    }

    bool GameComponent::RemoveChildByLocalID(LocalComponentID localID, bool destroy)
    {
        GameComponent* toRemove = GetChildByLocalID(localID);

        if(toRemove == NULL)
        {
            return false;
        }
        else
        {
            return RemoveChild(toRemove, destroy);
        }

        return false;
    }

    bool GameComponent::RemoveChildByGlobalID(GlobalComponentID globalID, bool destroy)
    {
        GameComponent* toRemove = GetChildByGlobalID(globalID);

        if(toRemove == NULL)
        {
            return false;
        }
        else
        {
            return RemoveChild(toRemove, destroy);
        }

        return false;
    }

    bool GameComponent::RemoveFirstChildWithName(const std::string& name, bool destroy)
    {
        GameComponent* toRemove = GetFirstChildByName(name);

        if(toRemove == NULL)
        {
            return false;
        }
        else
        {
            return RemoveChild(toRemove, destroy);
        }

        return false;
    }

    bool GameComponent::RemoveAllChildrenWithName(const std::string& name, bool destroy)
    {
        std::vector<GameComponent*> toRemove = GetAllChildrenWithName(name);

        if(toRemove.size() == 0)
        {
            return false;
        }

        bool toReturn = true;

        for(size_t i = 0; i < toRemove.size(); i++)
        {
            toReturn = toReturn && RemoveChild(toRemove[i], destroy);
        }

        return toReturn;
    }

    // Sets this component to be deleted, and does any other
    // special effects that the game requires.
    void GameComponent::Destroy()
    {
        m_isDestroyed = true;

        if(m_parent != NULL)
        {
            m_parent->RemoveChild(this, false);
        }
    }

    void GameComponent::SetLocalRotation(double angle)
    {
        m_localPose(0, 0) = cos(angle);
        m_localPose(0, 1) = -sin(angle);
        m_localPose(1, 0) = sin(angle);
        m_localPose(1, 1) = cos(angle);

        m_localRotation = angle;
    }

    void GameComponent::SetGlobalRotation(double angle)
    {
        m_globalPose(0, 0) = cos(angle);
        m_globalPose(0, 1) = -sin(angle);
        m_globalPose(1, 0) = sin(angle);
        m_globalPose(1, 1) = cos(angle);

        m_globalRotation = angle;
    }

    void GameComponent::HandleKeyEvent(QKeyEvent* keyEvent)
    {

    }

    void GameComponent::HandleMouseEvent(QMouseEvent* mouseEvent)
    {

    }


} /* namespace kling */
